home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D Images
/
3D Images.iso
/
programs
/
amiga
/
rayshade
/
inetray
/
inetray.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-12
|
15KB
|
573 lines
/*======================================================================
I N E T R A Y . C
doc: Mon Feb 24 16:20:04 1992
dlm: Tue Aug 17 13:51:54 1993
(c) 1992 ant@julia
uE-Info: 414 31 T 0 0 72 10 2 8 ofnI
======================================================================*/
/*#define PRINTSCHEDULE /* print scheduling info */
/*#define VERBOSE /* print retrys */
#include <stdio.h> /* here we go! */
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/param.h>
#include <rpc/rpc.h>
#include "inetray.h"
#include "config.h"
#include "common.h"
#include "comm.h"
#include "rayshade.h"
#include "options.h"
#include "picture.h"
#include "viewing.h"
#include "rcfile.h"
#include "lbuffer.h"
#include "version.h"
#include "patchlevel.h"
static Pixel **line; /* array for picture data */
static int bSize; /* blocksize to trace in one sweep */
static int lSize; /* size of last block in frame */
static int bNum; /* number of blocks in frame */
static char *completed; /* array for completed blocks */
static int doNext = 0; /* next block to trace */
static int doNBlk = 2; /* number of blocks to send */
static char pass2 = FALSE; /* 2nd pass through picture */
static int reDo = 0; /* reDo # of outstanding blocks */
static int nCompleted = 0; /* number of lines completed per frame */
static int bCompleted = 0; /* number of blocks completed per frame */
static int nSvc; /* number of registered servers */
static int nextB2W; /* next block to write to pic file */
static int bufPipe[2]; /* 2nd pipe to lBuffer */
static int tty; /* read from keyboard */
int key; /* session key (exported) */
extern int errno; /* error number to restart syscalls */
main(ac,av)
int ac; char *av[];
{
static void initSelf(),initSubDiv(),initFrame();
static void printStats(),distAll(),sigCaught(),writeBlocks();
static int initServers();
int fd;
char buf[64];
if ((tty = open("/dev/tty",O_RDONLY)) < 0) { /* keyboard */
perror("open(/dev/tty)");
exit(1);
}
fprintf(stderr,"%s [%s%d]\n",av[0],VERSION,PATCHLEVEL);
initSelf(ac,av); /* initialize self */
PictureStart(av); /* open picture file */
key = (int)time(NULL); /* session key */
fprintf(stderr,"Session Key = %d\n",key);
rename(KEYFILE,OLDKEYFILE); /* save keyfile */
fd = open(KEYFILE,O_CREAT|O_WRONLY,0600);
if (fd < 0) {
perror("open(KEYFILE)");
} else {
sprintf(buf,"%ld\n",key); /* in ASCII */
if (write(fd,buf,strlen(buf)) < 0) {
perror("write");
exit(1);
}
close(fd);
}
initServers(ac,av); /* set up all servers */
initSubDiv(); /* init frame subdivision */
for (Options.framenum=Options.startframe;
Options.framenum<=Options.endframe;
Options.framenum++) {
initFrame(Options.framenum); /* init & send first requests */
if (Options.framenum>Options.startframe)
PictureStart(av); /* write picture in parallel */
distAll(); /* distribute remaining lines */
writeBlocks(TRUE); /* write remaining blocks */
fprintf(stderr,"Cleaning up... [kill");
killAll(); /* kill running workers */
fprintf(stderr,", flush");
flushAll(); /* discard pending input */
fprintf(stderr,", wait");
waitAll(); /* wait for workers to come down */
fprintf(stderr,"]");
PictureFrameEnd(); /* end picture frame */
}
PictureEnd();
Options.framenum = Options.endframe; /* fix for stats */
printStats();
fprintf(stderr,"Exiting... [terminate");
terminateAll(); /* now exit everything */
fprintf(stderr,", close");
closeAll();
fprintf(stderr,"]\n");
exit(0);
}
/*----------------------------------------------------------------------*/
/* initSelf and supporting routines */
/*----------------------------------------------------------------------*/
static void busError() /* SUN4 weird bus errors */
{
fprintf(stderr,"Warning: SIGBUS caught!\n");
}
static void defSignals() /* install default sigs */
{
void sigCaught();
signal(SIGHUP,sigCaught); /* all sigs which could mean */
signal(SIGINT,sigCaught); /* terminate */
signal(SIGQUIT,sigCaught);
signal(SIGABRT,sigCaught);
signal(SIGTERM,sigCaught);
signal(SIGTSTP,sigCaught);
signal(SIGUSR1,sigCaught);
signal(SIGUSR2,sigCaught);
signal(SIGBUS,busError); /* sometimes on SUN4s */
signal(SIGPIPE,shutDown); /* ^C in pipeline */
}
static void sigCaught() /* abort signal rcved */
{
char ans;
fprintf(stderr,"\nSignal received...\n");
if (getppid() != 1) { /* parent alive */
fprintf(stderr,"Really abort <y/n>?");
do { /* get ans from keyboard */
if (read(tty,&ans,1) != 1) {
perror("read(tty)");
exit(1);
}
}
while ((ans != 'y') && (ans != 'Y') &&
(ans != 'n') && (ans != 'N'));
if ((ans == 'y') || (ans == 'Y')) shutDown(0);
} else shutDown(0);
defSignals();
}
static void initFrame(f) /* init frame */
int f;
{
int i;
void dist1st();
for (i=0; i<bNum; i++) /* clear completed flags */
completed[i] = FALSE;
doNext = nCompleted = 0; /* reset counters */
pass2 = FALSE;
reDo = nextB2W = bCompleted = 0;
fprintf(stderr,"\nFrame #%d:\n",f);
dist1st(f); /* begin trace */
}
static void initSelf(ac,av) /* init stuff */
int ac; char *av[];
{
int bPid,i,lnSize,saveIn,p[2];
readRc(); /* read .rc-file */
if (pipe(p) < 0) { /* set up input */
perror("pipe");
exit(1);
}
if (pipe(bufPipe) < 0) { /* 2nd lBuffer pipe */
perror("pipe");
exit(1);
}
bPid = lPreBuffer(p,bufPipe);
saveIn = dup(IN); /* redirect stdin */
close(IN);
dup(p[IN]);
close(p[IN]);
RSInitialize(ac,av); /* options, file, ... */
kill(bPid,SIGUSR1); /* kill if still killable */
close(IN); /* reset stdin */
dup(saveIn);
wait(NULL); /* from popen() */
defSignals(); /* signals */
line = (Pixel **)malloc(Screen.ysize * sizeof(Pixel *));
if (line == NULL) {
fprintf(stderr,"malloc() failed\n");
exit(1);
}
lnSize = Screen.xsize * sizeof(Pixel);
for (i=0; i<Screen.ysize; i++) {
line[i] = (Pixel *)malloc(lnSize);
if (line[i] == NULL) {
perror("malloc");
exit(1);
}
}
}
static void initSubDiv() /* init frame subdivision */
{
bSize = Screen.ysize / nSvc
/ blocksPerServer; /* estimated size of blocks */
if (bSize < minBlockSize) /* assert bounds */
bSize = minBlockSize;
if (bSize > maxBlockSize)
bSize = maxBlockSize;
bNum = Screen.ysize / bSize + 1; /* number of blocks */
lSize = Screen.ysize-(bNum-1)*bSize; /* remaining lines */
if (lSize == 0) { /* no remaining lines */
bNum--;
lSize = bSize;
}
completed = (char *)malloc(bNum); /* supporting structures */
if (completed == NULL) {
fprintf(stderr,"malloc() failed\n");
exit(1);
}
fprintf(stderr,"Frame Subdivision:");
fprintf(stderr,"\n\t%d Blocks per Frame",bNum);
fprintf(stderr,"\n\t%d Lines per Block",bSize);
if (lSize != bSize)
fprintf(stderr,"\n\t%d Lines in Last Block",lSize);
}
/*----------------------------------------------------------------------*/
/* distribution */
/*----------------------------------------------------------------------*/
static int findNext() /* next blockNr */
{
int i,sm= -1,nx= -1,next;
for (i=0; i<bNum; i++)
if (!completed[i]) {
if (sm < 0) sm = i;
if ((nx < 0) && (i >= doNext)) nx = i;
}
if (sm < 0) return FALSE;
if (nx < 0) { /* original next */
if (!pass2) {
fprintf(stderr,"\tEnd of Pass #1\n");
pass2 = TRUE;
}
next = sm;
} else next = nx;
if (reDo > 0) { /* rescheduled */
reDo--;
doNext = sm;
doNBlk = 1;
} else if (pass2 || next == bNum-1 || next == bNum-2) {
doNext = next;
doNBlk = 1;
} else {
doNext = next;
doNBlk = 2;
}
return TRUE;
}
static void dist1st(frame) /* dist 1 block p. server */
int frame;
{
hInfo *host;
int res,rpcerr,nTrys;
sfPrm paramSF;
for (host = hosts; host != NULL; host = host->next) {
if (!findNext()) return;
host->fDone = 0;
if (host->broken) continue;
paramSF.key = key;
paramSF.fNr = frame;
for (nTrys = 10; nTrys > 0; nTrys--) {
rpcerr = clnt_call(host->clnt,STARTFRAME,
xdr_sfPrm,¶mSF,
xdr_int,&res,callTOut);
if (rpcerr == RPC_SUCCESS) break;
if (rpcerr == RPC_TIMEDOUT) {
#ifdef VERBOSE
fprintf(stderr,"STARTFRAME retry to %s\n",host->name);
#endif
host->reTrys++;
if (nTrys > 1) continue;
}
fprintf(stderr,"startframe(): ");
abort1(host);
}
host->request.key = key;
host->request.bNr = doNext;
host->request.bSz = (doNext == bNum-1) ? lSize : bSize;
host->request.lNr = doNext*bSize;
host->request.nBlocks = doNBlk;
clnt_call(host->clnt,TRACEBLOCK,
xdr_tbPrm,&(host->request),
xdr_void,NULL,now);
#ifdef PRINTSCHEDULE
fprintf(stderr,"\tBlock(s) #%d-#%d sent to %s(%d)\n",
doNext,doNext+doNBlk-1,host->name,host->wid);
#endif
doNext += doNBlk;
}
}
static void printStats() /* print statistics */
{
hInfo *host,*bHost;
int tot,all,best;
char nBuf[MAXHOSTNAMELEN+10];
if (getppid() == 1) shutDown(0);
signal(SIGINT,sigCaught);
fprintf(stderr,"\nStatistics:\n");
tot = (Options.framenum-Options.startframe)*Screen.ysize+nCompleted;
if (tot == 0) tot = 1;
for (all=0; all<nSvc; all++) {
best = 0;
for (host = hosts; host != NULL; host = host->next)
if (host->done >= best) {
best = host->done;
bHost = host;
}
if (bHost->done == 0) bHost->done = -1;
else bHost->done = -bHost->done;
putc('\t',stderr);
sprintf(nBuf,"%s[%d]",bHost->name,bHost->pid);
fprintf(stderr,"\t%-15.14s",nBuf);
if (bHost->broken) fprintf(stderr,"# ");
else fprintf(stderr," ");
if (bHost->reTrys != 0)
fprintf(stderr,"%4d",bHost->reTrys);
fprintf(stderr,"\t");
fprintf(stderr,"%d \t(%d%%)\n",best,100*best/tot);
}
for (host = hosts; host != NULL; host = host->next)
if (host->done == -1) host->done = 0;
else host->done = -host->done;
if (getppid() == 1) shutDown(0);
}
static void writeBlocks(flush)
char flush;
{
int i,bSz,writ = 0; /* write to file */
hInfo *h;
fd_set sockSet;
while ((nextB2W < bNum) && completed[nextB2W]) {
if (writ == 0)
fprintf(stderr,"\tWriting... ");
bSz = (nextB2W == bNum-1) ? lSize : bSize;
for (i=0; i<bSz; i++)
PictureWriteLine(line[nextB2W*bSize+i]);
nextB2W++; writ++;
if (!flush) { /* check for input */
FD_ZERO(&sockSet);
for (h = hosts; h != NULL; h = h->next)
if (!h->broken)
FD_SET(h->sock,&sockSet);
if (select(sfdmax+1,&sockSet,
(fd_set *)NULL,(fd_set *)NULL,
&now) != 0) {
fprintf(stderr,"[interrupted] ");
break;
}
}
}
if (writ == 1) /* report it */
fprintf(stderr,"(1 block)\n");
else if (writ > 1)
fprintf(stderr,"(%d blocks)\n",writ);
}
static char getBlock(host) /* get traced block */
hInfo *host;
{
pixArr xdrline;
int bNr,bSz,i; /* block info */
XDR *xdrs;
hInfo *h;
xdrs = &(host->xdrs);
if (!xdrrec_skiprecord(xdrs)) { /* read next record*/
fprintf(stderr,"xdrrec_skiprecord(): ");
abort1(host);
return FALSE;
}
if (!xdr_int(xdrs,&bNr)) { /* get block number */
abort1(host);
return FALSE;
}
bSz = (bNr == bNum-1) ? lSize : bSize; /* calc block size */
for (i=0; i<bSz; i++) { /* read all lines */
xdrline.pixArr_val = (xdrPix *)line[bNr*bSize+i];
if (!xdr_pixArr(xdrs,&xdrline)) {
fprintf(stderr,"xdr_pixArr(): ");
abort1(host);
return FALSE;
}
}
host->request.nBlocks--;
#ifdef PRINTSCHEDULE
fprintf(stderr,"\tBlock #%d received from %s(%d)\n",
bNr,host->name,host->wid);
fprintf(stderr,"\t%d Block(s) remaining\n",
host->request.nBlocks);
#endif
if (!completed[bNr]) { /* reporting & statistics */
completed[bNr] = TRUE;
if (nCompleted/Options.report_freq <
(nCompleted+bSz)/Options.report_freq) {
fprintf(stderr,"\tFinished line %d\n",nCompleted+bSz);
}
nCompleted += bSz; /* update stats */
bCompleted++;
host->done += bSz;
host->fDone += bSz;
/* if (bCompleted == bNum/2) {
for (h = hosts; h != NULL; h = h->next)
if (h->fDone == 0) reDo++;
if (reDo > bNum/4) reDo = 0;
reDo *= 2;
if (reDo == 1)
fprintf(stderr,"\t1 block rescheduled\n");
else
fprintf(stderr,"\t%d blocks rescheduled\n",reDo);
} */
}
writeBlocks(FALSE);
return TRUE;
}
static void distAll() /* block distribution routine */
{
fd_set sockSet;
int res;
hInfo *host;
char timedOut;
do { /* loop on all blocks */
signal(SIGINT,printStats);
restartSelect:
FD_ZERO(&sockSet); /* select() on sockets */
for (host = hosts; host != NULL; host = host->next)
if (!host->broken)
FD_SET(host->sock,&sockSet);
timedOut = TRUE;
res = select(sfdmax+1,&sockSet,
(fd_set *)NULL,(fd_set *)NULL,
&resend);
if (res < 0) {
if (errno == EINTR) goto restartSelect;
perror("select");
exit(1);
}
for (host = hosts; host != NULL; host = host->next) {
if (!FD_ISSET(host->sock,&sockSet)) continue;
if (host->broken) continue;
timedOut = FALSE;
if (!getBlock(host)) /* read one result */
continue; /* connection broken */
if (host->request.nBlocks > 0) /* not done yet */
continue;
if (!findNext()) return; /* next line to trace */
host->request.key = key; /* next block */
host->request.bNr = doNext;
host->request.bSz = (doNext == bNum-1) ? lSize : bSize;
host->request.lNr = doNext * bSize;
host->request.nBlocks = doNBlk;
(void)clnt_call(host->clnt,TRACEBLOCK,
xdr_tbPrm,&(host->request),
xdr_void,NULL,
now);
#ifdef PRINTSCHEDULE
fprintf(stderr,"\tBlock(s) #%d-#%d sent to %s(%d)\n",
doNext,doNext+doNBlk-1,host->name,host->wid);
#endif
doNext += doNBlk;
}
} FOREVER;
}
/*----------------------------------------------------------------------*/
/* initClients() */
/*----------------------------------------------------------------------*/
static char *makePStr(ac,av) /* build param-str */
int ac; char *av[];
{
int abp,ap,i;
static char argbuf[256];
for (abp=0,ap=0; ap < ac; ap++) {
argbuf[abp++] = '\'';
for (i=0; av[ap][i] != '\0'; i++)
argbuf[abp++] = av[ap][i];
argbuf[abp++] = '\'';
argbuf[abp++] = ' ';
}
argbuf[abp] = '\0';
return argbuf;
}
static int initServers(ac,av) /* init all servers */
int ac; char *av[];
{
char cwd[MAXPATHLEN],hname[MAXHOSTNAMELEN];
char *getcwd();
struct stat sBuf;
if (gethostname(hname,MAXHOSTNAMELEN) < 0) {
perror("gethostname");
exit(1);
}
if (fstat(bufPipe[IN],&sBuf) < 0) { /* buffer alive? */
perror("fstat");
exit(1);
}
fprintf(stderr,"Registering... [");
registerSvc(hname,makePStr(ac,av),
getcwd(cwd,MAXPATHLEN),sBuf.st_size>0);
nSvc = nRunning;
if (nSvc == 0) {
fprintf(stderr,"\nError: no Inetray Servers answering!\n");
exit(1);
}
fprintf(stderr,"\n[%d workers registered]\n",nSvc);
if (sBuf.st_size>0) { /* send file */
fprintf(stderr,"Distibuting StdIn...");
distribute(bufPipe[IN]);
fprintf(stderr,"\n");
}
wait(NULL); /* wait for buffer */
}